<!DOCTYPE html>


<html lang="zh-CN">


<head>
  <meta charset="utf-8" />
  <meta name="baidu_union_verify" content="0423ec0cdca4f8eebe6e059172fc0e94">
  <meta name="baidu-site-verification" content="code-pR8Cu8CCAR" />
  <meta name="google-site-verification" content="kPx7uwBYN8ZNVw-1hPQgk5yziYYGu7ZawLlYvgTblwQ" />
  <meta name="sogou_site_verification" content="bt3Su26Lme"/>
  <meta name="360-site-verification" content="73ba99e99d3fc1e5f8a37d8c1d998703" />
   
  <meta name="keywords" content="LIEFox,liefox,liefox拾柒,LIEFox拾柒,编程笔记,JAVA,前端" />
   
  <meta name="description" content="LIEFox一个有趣又好玩的学习编程网站" />
  
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
  <title>
    面向对象基础 |  LIEFox
  </title>
  <meta name="generator" content="hexo-theme-ayer">
  
  <link rel="shortcut icon" href="/favicon.ico" />
  
  
<link rel="stylesheet" href="/dist/main.css">

  
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/css/remixicon.min.css">

  
<link rel="stylesheet" href="/css/custom.css">

  
  
<script src="https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js"></script>

  
  

  
<script>
var _hmt = _hmt || [];
(function() {
	var hm = document.createElement("script");
	hm.src = "https://hm.baidu.com/hm.js?70837313b75a2b48b1e427bcabe5c0d9";
	var s = document.getElementsByTagName("script")[0]; 
	s.parentNode.insertBefore(hm, s);
})();
</script>



<script>
(function(){
    var bp = document.createElement('script');
    var curProtocol = window.location.protocol.split(':')[0];
    if (curProtocol === 'https') {
        bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';        
    }
    else {
        bp.src = 'http://push.zhanzhang.baidu.com/push.js';
    }
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(bp, s);
})();
</script>

<!-- 封面标闪烁 -->
<link rel="stylesheet" href="/css/zhyBlogTitle.css">

<!-- Highlight.js -->
<link href="https://cdn.bootcdn.net/ajax/libs/highlight.js/9.18.1/styles/a11y-dark.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/highlight.js/9.18.1/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>

</head>

</html>

<body>
  <div id="app">
    
      
      <canvas width="1777" height="841"
        style="position: fixed; left: 0px; top: 0px; z-index: 99999; pointer-events: none;"></canvas>
      
    <main class="content on">
      <section class="outer">
  <article
  id="post-面向对象基础"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h1 class="article-title sea-center" style="border-left:0" itemprop="name">
  面向对象基础
</h1>
 

    </header>
     
    <div class="article-meta">
      <a href="/posts/9d9ad23f.html" class="article-date">
  <time datetime="2020-12-03T16:00:00.000Z" itemprop="datePublished">2020-12-04</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/JAVA%E7%AC%94%E8%AE%B0/">JAVA笔记</a>
  </div>
  
<div class="word_count">
    <span class="post-time">
        <span class="post-meta-item-icon">
            <i class="ri-quill-pen-line"></i>
            <span class="post-meta-item-text"> 字数统计:</span>
            <span class="post-count">9.9k</span>
        </span>
    </span>

    <span class="post-time">
        &nbsp; | &nbsp;
        <span class="post-meta-item-icon">
            <i class="ri-book-open-line"></i>
            <span class="post-meta-item-text"> 阅读时长≈</span>
            <span class="post-count">40 分钟</span>
        </span>
    </span>
</div>
 
    </div>
      
    <div class="tocbot"></div>




  
    <div class="article-entry" itemprop="articleBody">
       
  <p><a href="https://cxq21.gitee.io/posts/9d9ad23f.html"><img src="https://s3.ax1x.com/2021/01/09/sM0Lc9.png" alt="sM0Lc9.png" style="zoom: 25%;" /></a></p>
<a id="more"></a>

<h1 id="（1）面向对象的概念"><a href="#（1）面向对象的概念" class="headerlink" title="（1）面向对象的概念"></a>（1）面向对象的概念</h1><p>面向对象是一种符合人类思维的编程思想，将万物比作对象，说一个栗子：</p>
<p><strong>把大象装进冰箱需要几步</strong></p>
<p>三步</p>
<ol>
<li>打开冰箱</li>
<li>装进大象</li>
<li>关上冰箱门</li>
</ol>
<p><strong>这个是一个典型的面向过程的编程思想，把这个事情，像成敲java代码，如果换成装狐狸，那也要重新写一遍代码，将狐狸放进冰箱，执行三步，如果又换把狐狸放进笼子里呢，又要重新写一遍。所以为了解决事情的重复性，就有了面向对象思想。</strong></p>
<p>就可以将装进某件事物封装成一个对象，只需要改动一点点，就可以实现这个功能。。。。</p>
<p>而面向对象有三个特点：</p>
<p>1.封装性</p>
<p>封装性是将对象的属性和行为封装起来，然后不需要让用户知道他是怎么执行的，只需要改变对应的参数，就可以实现用户想要达到的功能。</p>
<p>2.继承性</p>
<p>继承性主要讲的是类与类之间的关系，可以通过继承将代码的冗余降低。用最少的代码，做更多的功能。</p>
<p>3.多态性</p>
<p>多态性是指程序之间允许出现重名的现象。在继承关系中，子类如果定义了一个与父类方法签名完全相同的方法，被称为覆写（Override）。</p>
<h1 id="（2）方法"><a href="#（2）方法" class="headerlink" title="（2）方法"></a>（2）方法</h1><p>首先，在当讲面向对象前，我们来先了解一下方法，方法简单来说就是一个小功能，将代码封装成一个方法，使开发者可以重复使用，避免代码的冗余，具体可以看下面这个例子：</p>
<p>​    我定义了一个Demo的类，里面有一个<code>PrintB()</code>的方法,功能可以打印4个BBBB；当<code>main</code>方法里面调用了方法名 <code>PrintB（）</code>，就可以打印出四个B。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Demo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span>  <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">PrintB</span><span class="params">()</span></span>&#123;</span><br><span class="line">        System.out.print(<span class="string">&quot;B&quot;</span>);</span><br><span class="line">        System.out.print(<span class="string">&quot;B&quot;</span>);</span><br><span class="line">        System.out.print(<span class="string">&quot;B&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;B&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        PrintB();</span><br><span class="line">        System.out.println(<span class="string">&quot;--------&quot;</span>);</span><br><span class="line">        PrintB();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">打印结果</span><br><span class="line">BBBB</span><br><span class="line">--------</span><br><span class="line">BBBB</span><br></pre></td></tr></table></figure>

<h3 id="注意："><a href="#注意：" class="headerlink" title="注意："></a><code>注意：</code></h3><ol>
<li>方法可以重复调用</li>
<li>方法必须定义在类（class）里面</li>
<li>不可以在方法里面创建的方法，必须为兄弟级</li>
<li>同一个类中方法名不可重复</li>
<li>一个类中可以写多个方法</li>
<li>定义方法不分先后顺序</li>
<li>方法必须先定义，后执行</li>
<li>如果一个方法前面有static修饰，在该方法调用其他方法的时候，其他方法也需要被static修饰</li>
</ol>
<h3 id="定义方法"><a href="#定义方法" class="headerlink" title="定义方法"></a>定义方法</h3><p>方法的格式是</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">【修饰符】返回值类型 方法名 （【形式参数。。。】）&#123;</span><br><span class="line">	方法体</span><br><span class="line">	【<span class="keyword">return</span> 返回值类型】</span><br><span class="line">&#125;<span class="comment">//【】里的可有可无</span></span><br></pre></td></tr></table></figure>

<p><code>注意：</code></p>
<ol>
<li>修饰符可以以是 <code>public</code> &amp; <code>static</code> ，但在定义的时候不一定要写。</li>
<li>当返回值类型填的是<code>void</code>时，<code>return</code>就可不写，当返回值类型为 <code>String</code> 时，<code>return</code> 的返回对象就是 <code>String</code>。</li>
<li>方法名最好见名知意，并运用驼峰命名法，不可违背Java的命名规范。</li>
<li>形式参数可有可无，具体要看方法定义的功能，可以接收传递的参数，多个参数用逗号隔开，调用时要注意顺序和类型。</li>
</ol>
<p>来个栗子：</p>
<h4 id="来写一个关于方法参数的加法计算器的小练习"><a href="#来写一个关于方法参数的加法计算器的小练习" class="headerlink" title="来写一个关于方法参数的加法计算器的小练习"></a>来写一个关于方法参数的加法计算器的小练习</h4><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Demo</span> &#123;</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">Sum</span><span class="params">(<span class="keyword">int</span> a,<span class="keyword">int</span> b)</span></span>&#123;<span class="comment">//获取2个参数</span></span><br><span class="line">        System.out.<span class="built_in">print</span>(a+b);<span class="comment">//打印a+b</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">String</span>[] args)</span> </span>&#123;</span><br><span class="line">        Sum(<span class="number">300</span>,<span class="number">2001</span>);<span class="comment">//调用Sum方法，并传入2个int类型的参数</span></span><br><span class="line">    &#125;<span class="comment">//结果：2301</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="再来写一个关于返回值的加法计算器的小练习"><a href="#再来写一个关于返回值的加法计算器的小练习" class="headerlink" title="再来写一个关于返回值的加法计算器的小练习"></a>再来写一个关于返回值的加法计算器的小练习</h4><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Demo</span> &#123;</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">Sum</span><span class="params">(<span class="keyword">int</span> a,<span class="keyword">int</span> b)</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> sum =a+b;</span><br><span class="line">        <span class="keyword">return</span> sum;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">String</span>[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> sum = Sum(<span class="number">11</span>, <span class="number">11</span>);</span><br><span class="line">        System.out.<span class="built_in">println</span>(sum);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;<span class="comment">//结果：22</span></span><br></pre></td></tr></table></figure>

<p>相比第一个加法计算器来说，第二个练习会稍微复杂一点点，但目的是为了让大家更好去了解值传递的过程。</p>
<h4 id="现在来在来做一个登录的小练习"><a href="#现在来在来做一个登录的小练习" class="headerlink" title="现在来在来做一个登录的小练习"></a>现在来在来做一个登录的小练习</h4><p>运用到的知识点有：</p>
<ul>
<li>if判断</li>
<li>&amp;&amp;短路与</li>
<li>方法的返回值</li>
<li>方法的值传递</li>
</ul>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Demo2</span> </span>&#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 登录功能</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param </span>userName：用户名，设置成 zjh</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param </span>passWord：密码，设置成 123456</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">String</span> login (<span class="built_in">String</span> userName ,<span class="built_in">String</span> passWord)&#123;</span><br><span class="line">        <span class="keyword">if</span> (userName==<span class="string">&quot;zjh&quot;</span>&amp;&amp;passWord==<span class="string">&quot;123456&quot;</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;登录成功&quot;</span>;</span><br><span class="line">        &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;登录失败&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">void</span> <span class="function"><span class="title">main</span>(<span class="params"><span class="built_in">String</span>[] args</span>)</span> &#123;</span><br><span class="line">        <span class="built_in">String</span> login = login(<span class="string">&quot;zjh&quot;</span>, <span class="string">&quot;123456&quot;</span>);</span><br><span class="line">        System.out.println(login);</span><br><span class="line">    &#125;<span class="comment">//得到的结果是，登录成功，自己可以写下来多尝试，并优化一些功能，比如提醒用户输入，需要用到的点是 Scanner</span></span><br><span class="line">&#125;	</span><br></pre></td></tr></table></figure>

<h3 id="方法的重载"><a href="#方法的重载" class="headerlink" title="方法的重载"></a>方法的重载</h3><p>在一个类中，我们可以定义多个方法。如果有一系列方法，它们的功能都是类似的，只有参数有所不同，那么，可以把这一组方法名做成<em>同名</em>方法。例如，在<code>Demo</code>类中，定义多个<code>Sum()</code>方法：</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Demo</span> &#123;</span></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     *  更多类型求和（方法的重载）</span></span><br><span class="line"><span class="comment">     * @param a:第一个数</span></span><br><span class="line"><span class="comment">     * @param b:第二个数</span></span><br><span class="line"><span class="comment">     * @return</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">Sum</span><span class="params">(<span class="keyword">int</span> a,<span class="keyword">int</span> b)</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> sum =a+b;</span><br><span class="line">        <span class="keyword">return</span> sum;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">double</span> <span class="title">Sum</span><span class="params">(<span class="keyword">double</span> a,<span class="keyword">double</span> b)</span></span>&#123;</span><br><span class="line">        <span class="keyword">double</span> sum =a+b;</span><br><span class="line">        <span class="keyword">return</span> sum;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">String</span>[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> sum1 = Sum(<span class="number">11</span>, <span class="number">11</span>);</span><br><span class="line">        System.out.<span class="built_in">println</span>(sum1);</span><br><span class="line">        System.out.<span class="built_in">println</span>(<span class="string">&quot;---------&quot;</span>);</span><br><span class="line">        <span class="keyword">double</span> sum2 = Sum(<span class="number">11.11</span>, <span class="number">22.22</span>);</span><br><span class="line">        System.out.<span class="built_in">println</span>(sum2);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//打印的结果</span></span><br><span class="line">     <span class="number">22</span></span><br><span class="line">	---------</span><br><span class="line">	 <span class="number">33.33</span>	</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这种方法名相同，但各自的参数不同，称为方法重载（<code>Overload</code>）。</p>
<p>注意：仅仅返回值类型不同，不足以是方法的重载。</p>
<p>方法重载的目的是，功能类似的方法使用同一名字，更容易记住，因此，调用起来更简单。</p>
<h1 id="（3）面向过程"><a href="#（3）面向过程" class="headerlink" title="（3）面向过程"></a>（3）面向过程</h1><p>再来了解一下什么是面向过程，对后面的了解面向对象就更加好的理解。</p>
<h3 id="概念："><a href="#概念：" class="headerlink" title="概念："></a><code>概念</code>：</h3><ul>
<li>是站在过程的编程思维，强调的是功能行为，功能的执行过程，即先干啥，后干啥</li>
<li>而每一个功能我们都使用函数（类似于方法）一步步调用，使用的时候依次调用就好了</li>
<li>按照顺序一步步去做</li>
</ul>
<h3 id="面向过程的设计"><a href="#面向过程的设计" class="headerlink" title="面向过程的设计"></a>面向过程的设计</h3><p>最小的程序单元是函数，每一个函数实现的是某一个功能，从主函数（main）依次调用对应函数，其他函数可以任意互相调用，来完成整个程序的功能。</p>
<h3 id="面向过程的缺陷"><a href="#面向过程的缺陷" class="headerlink" title="面向过程的缺陷"></a>面向过程的缺陷</h3><p>设计功能是从上至下，在设计程序时要考虑每一个模块，并且去细分成更多的子模块。如此类推，要将每一个模块细分成一个个函数。</p>
<p><code>说了这么多废话，肯定面向过程不适合我们开发的思维，而面向对象更符合我们。</code></p>
<h1 id="（4）面向对象"><a href="#（4）面向对象" class="headerlink" title="（4）面向对象"></a>（4）面向对象</h1><p>千呼万唤始出来，犹抱键盘半遮面！</p>
<p>那么，面向对象和面向过程究竟有什么区别呢？举个栗子就明白了。</p>
<p><strong>面向对象：</strong></p>
<p>平常我们去饭店吃饭，就只用和服务员点菜，过一会，服务员就会把你点的菜端上来。你无需去关注菜是怎么做的，就只用发送命令就可以完成你想要的结果。</p>
<p><strong>面向过程：</strong></p>
<p>面向过程就没有了饭店这个东西，你要吃饭，就必须亲力亲为，从买菜，洗菜，切菜，开火，下油。。。。。直到上菜。这些事情都需要你去操作。</p>
<h2 id="类"><a href="#类" class="headerlink" title="类"></a>类</h2><p>某一个具体对象特征的抽象，把多个对象共同的特征、属性、状态、行为给抽象出来。</p>
<p>比如：</p>
<p><img src="https://i.loli.net/2021/01/18/YP1A4gortUCi9Fk.jpg" alt="_BBE7DC1C-1086-461A-BF4E-0848F61DA9DD_.png.jpg">  </p>
<h2 id="构造器"><a href="#构造器" class="headerlink" title="构造器"></a>构造器</h2><p>创建实例的时候，实际上是通过构造方法来初始化实例的。我们先来定义一个构造方法，能在创建<code>Person</code>实例的时候，一次性传入<code>name</code>和<code>age</code>，完成初始化：</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Demo</span> &#123;</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">String</span>[] args)</span> </span>&#123;</span><br><span class="line">        Person person = <span class="keyword">new</span> Person(<span class="string">&quot;LIEfox&quot;</span>, <span class="number">12</span>);</span><br><span class="line">        System.out.<span class="built_in">println</span>(person.getName());</span><br><span class="line">        System.out.<span class="built_in">println</span>(person.getAge());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span>&#123;</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">String</span> Name;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> Age;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Person</span><span class="params">(<span class="keyword">String</span> name, <span class="keyword">int</span> age)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.Name = name;</span><br><span class="line">        <span class="keyword">this</span>.Age = age;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">String</span> <span class="title">getName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> Name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getAge</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> Age;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//打印结果</span></span><br><span class="line">LIEFox</span><br><span class="line"><span class="number">12</span></span><br></pre></td></tr></table></figure>

<p>由于构造方法是如此特殊，所以构造方法的名称就是类名。构造方法的参数没有限制，在方法内部，也可以编写任意语句。但是，和普通方法相比，构造方法没有返回值（也没有<code>void</code>），调用构造方法，必须用<code>new</code>操作符。</p>
<p>构造方法有默认的，如果没有定义，Java虚拟机会自动给你定义一个默认的构造器，他长这个样子：</p>
<figure class="highlight actionscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Person（）&#123;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>要特别注意的是，如果我们自定义了一个构造方法，那么，编译器就<em>不再</em>自动创建默认构造方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Person p = <span class="keyword">new</span> Person(); <span class="comment">// 编译错误:找不到这个构造方法</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> age;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Person</span><span class="params">(String name, <span class="keyword">int</span> age)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">        <span class="keyword">this</span>.age = age;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getAge</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.age;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如果既要能使用带参数的构造方法，又想保留不带参数的构造方法，那么只能把两个构造方法都定义出来。没有在构造方法中初始化字段时，引用类型的字段默认是<code>null</code>，数值类型的字段用默认值，<code>int</code>类型默认值是<code>0</code>，布尔类型默认值是<code>false</code>。</p>
<p>多构造方法可以这样定义，实现类似重载的功能，</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="function"><span class="title">Person</span>(<span class="params"><span class="built_in">String</span> name, int age</span>)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">        <span class="built_in">this</span>.age = age;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="function"><span class="title">Person</span>(<span class="params"><span class="built_in">String</span> name</span>)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>会自动匹配参数，当你</p>
<figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">Person person</span> = new Person(<span class="string">&quot;LIEfox&quot;</span>, 12);</span><br></pre></td></tr></table></figure>

<p>就会匹配</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">Person</span><span class="params">(<span class="keyword">String</span> name, <span class="keyword">int</span> age)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">        <span class="keyword">this</span>.age = age;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>当你</p>
<figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">Person person</span> = new Person(<span class="string">&quot;LIEfox&quot;</span>);</span><br></pre></td></tr></table></figure>

<p>就会</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="function"><span class="title">Person</span>(<span class="params"><span class="built_in">String</span> name</span>)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="（5）继承"><a href="#（5）继承" class="headerlink" title="（5）继承"></a>（5）继承</h1><p>在前面的章节中，我们已经定义了<code>Person</code>类：</p>
<figure class="highlight nim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">class <span class="type">Person</span> &#123;</span><br><span class="line">    private <span class="type">String</span> name;</span><br><span class="line">    private <span class="built_in">int</span> age;</span><br><span class="line"></span><br><span class="line">    public <span class="type">String</span> getName() <span class="meta">&#123;...&#125;</span></span><br><span class="line">    public <span class="built_in">void</span> setName(<span class="type">String</span> name) <span class="meta">&#123;...&#125;</span></span><br><span class="line">    public <span class="built_in">int</span> getAge() <span class="meta">&#123;...&#125;</span></span><br><span class="line">    public <span class="built_in">void</span> setAge(<span class="built_in">int</span> age) <span class="meta">&#123;...&#125;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>现在，假设需要定义一个<code>Student</code>类，字段如下：</p>
<figure class="highlight nim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">class <span class="type">Student</span> &#123;</span><br><span class="line">    private <span class="type">String</span> name;</span><br><span class="line">    private <span class="built_in">int</span> age;</span><br><span class="line">    private <span class="built_in">int</span> score;</span><br><span class="line"></span><br><span class="line">    public <span class="type">String</span> getName() <span class="meta">&#123;...&#125;</span></span><br><span class="line">    public <span class="built_in">void</span> setName(<span class="type">String</span> name) <span class="meta">&#123;...&#125;</span></span><br><span class="line">    public <span class="built_in">int</span> getAge() <span class="meta">&#123;...&#125;</span></span><br><span class="line">    public <span class="built_in">void</span> setAge(<span class="built_in">int</span> age) <span class="meta">&#123;...&#125;</span></span><br><span class="line">    public <span class="built_in">int</span> getScore() &#123; … &#125;</span><br><span class="line">    public <span class="built_in">void</span> setScore(<span class="built_in">int</span> score) &#123; … &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>仔细观察，发现<code>Student</code>类包含了<code>Person</code>类已有的字段和方法，只是多出了一个<code>score</code>字段和相应的<code>getScore()</code>、<code>setScore()</code>方法。</p>
<p>能不能在<code>Student</code>中不要写重复的代码？</p>
<p>这个时候，继承就派上用场了。</p>
<p>继承是面向对象编程中非常强大的一种机制，它首先可以复用代码。当我们让<code>Student</code>从<code>Person</code>继承时，<code>Student</code>就获得了<code>Person</code>的所有功能，我们只需要为<code>Student</code>编写新增的功能。</p>
<p>Java使用<code>extends</code>关键字来实现继承：</p>
<figure class="highlight nim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">class <span class="type">Person</span> &#123;</span><br><span class="line"> private <span class="type">String</span> name;</span><br><span class="line">    private <span class="built_in">int</span> age;</span><br><span class="line"></span><br><span class="line">    public <span class="type">String</span> getName() <span class="meta">&#123;...&#125;</span></span><br><span class="line">    public <span class="built_in">void</span> setName(<span class="type">String</span> name) <span class="meta">&#123;...&#125;</span></span><br><span class="line">    public <span class="built_in">int</span> getAge() <span class="meta">&#123;...&#125;</span></span><br><span class="line">    public <span class="built_in">void</span> setAge(<span class="built_in">int</span> age) <span class="meta">&#123;...&#125;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">class <span class="type">Student</span> extends <span class="type">Person</span> &#123;</span><br><span class="line">    // 不要重复name和age字段/方法,</span><br><span class="line">    // 只需要定义新增score字段/方法:</span><br><span class="line">    private <span class="built_in">int</span> score;</span><br><span class="line"></span><br><span class="line">    public <span class="built_in">int</span> getScore() &#123; … &#125;</span><br><span class="line">    public <span class="built_in">void</span> setScore(<span class="built_in">int</span> score) &#123; … &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>可见，通过继承，<code>Student</code>只需要编写额外的功能，不再需要重复代码。</p>
<p><code>注意</code>：子类自动获得了父类的所有字段，严禁定义与父类重名的字段！</p>
<p>在OOP的术语中，我们把<code>Person</code>称为超类（super class），父类（parent class），基类（base class），把<code>Student</code>称为子类（subclass），扩展类（extended class）。</p>
<h3 id="继承树"><a href="#继承树" class="headerlink" title="继承树"></a>继承树</h3><p>注意到我们在定义<code>Person</code>的时候，没有写<code>extends</code>。在Java中，没有明确写<code>extends</code>的类，编译器会自动加上<code>extends Object</code>。所以，任何类，除了<code>Object</code>，都会继承自某个类。下图是<code>Person</code>、<code>Student</code>的继承树：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">┌───────────┐</span><br><span class="line">│  Object   │</span><br><span class="line">└───────────┘</span><br><span class="line">      ▲</span><br><span class="line">      │</span><br><span class="line">┌───────────┐</span><br><span class="line">│  Person   │</span><br><span class="line">└───────────┘</span><br><span class="line">      ▲</span><br><span class="line">      │</span><br><span class="line">┌───────────┐</span><br><span class="line">│  Student  │</span><br><span class="line">└───────────┘</span><br></pre></td></tr></table></figure>

<p>Java只允许一个class继承自一个类，因此，一个类有且仅有一个父类。只有<code>Object</code>特殊，它没有父类。</p>
<p>类似的，如果我们定义一个继承自<code>Person</code>的<code>Teacher</code>，它们的继承树关系如下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">       ┌───────────┐</span><br><span class="line">       │  Object   │</span><br><span class="line">       └───────────┘</span><br><span class="line">             ▲</span><br><span class="line">             │</span><br><span class="line">       ┌───────────┐</span><br><span class="line">       │  Person   │</span><br><span class="line">       └───────────┘</span><br><span class="line">          ▲     ▲</span><br><span class="line">          │     │</span><br><span class="line">          │     │</span><br><span class="line">┌───────────┐ ┌───────────┐</span><br><span class="line">│  Student  │ │  Teacher  │</span><br><span class="line">└───────────┘ └───────────┘</span><br></pre></td></tr></table></figure>

<h3 id="protected"><a href="#protected" class="headerlink" title="protected"></a>protected</h3><p>继承有个特点，就是子类无法访问父类的<code>private</code>字段或者<code>private</code>方法。例如，<code>Student</code>类就无法访问<code>Person</code>类的<code>name</code>和<code>age</code>字段：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">String</span> name;</span><br><span class="line">    <span class="keyword">private</span> int age;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Student</span> <span class="keyword">extends</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    public <span class="type">String</span> hello() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Hello, &quot;</span> + name; <span class="comment">// 编译错误：无法访问name字段</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这使得继承的作用被削弱了。为了让子类可以访问父类的字段，我们需要把<code>private</code>改为<code>protected</code>。用<code>protected</code>修饰的字段可以被子类访问：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> <span class="type">String</span> name;</span><br><span class="line">    <span class="keyword">protected</span> int age;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Student</span> <span class="keyword">extends</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    public <span class="type">String</span> hello() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Hello, &quot;</span> + name; <span class="comment">// OK!</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>因此，<code>protected</code>关键字可以把字段和方法的访问权限控制在继承树内部，一个<code>protected</code>字段和方法可以被其子类，以及子类的子类所访问，后面我们还会详细讲解。</p>
<h3 id="super"><a href="#super" class="headerlink" title="super"></a>super</h3><p><code>super</code>关键字表示父类（超类）。子类引用父类的字段时，可以用<code>super.fieldName</code>。例如：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Student</span> <span class="keyword">extends</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    public <span class="type">String</span> hello() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Hello, &quot;</span> + <span class="keyword">super</span>.name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>实际上，这里使用<code>super.name</code>，或者<code>this.name</code>，或者<code>name</code>，效果都是一样的。编译器会自动定位到父类的<code>name</code>字段。</p>
<p>但是，在某些时候，就必须使用<code>super</code>。我们来看一个例子：</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> &#123;</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">String</span>[] args)</span> </span>&#123;</span><br><span class="line">        Student s = <span class="keyword">new</span> Student(<span class="string">&quot;Xiao Ming&quot;</span>, <span class="number">12</span>, <span class="number">89</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> &#123;</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">String</span> name;</span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">int</span> age;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Person</span><span class="params">(<span class="keyword">String</span> name, <span class="keyword">int</span> age)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">        <span class="keyword">this</span>.age = age;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Student</span> <span class="title">extends</span> <span class="title">Person</span> &#123;</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">int</span> score;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Student</span><span class="params">(<span class="keyword">String</span> name, <span class="keyword">int</span> age, <span class="keyword">int</span> score)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.score = score;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>运行上面的代码，会得到一个编译错误，大意是在<code>Student</code>的构造方法中，无法调用<code>Person</code>的构造方法。</p>
<p>这是因为在Java中，任何<code>class</code>的构造方法，第一行语句必须是调用父类的构造方法。如果没有明确地调用父类的构造方法，编译器会帮我们自动加一句<code>super();</code>，所以，<code>Student</code>类的构造方法实际上是这样：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Student</span> <span class="keyword">extends</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> int score;</span><br><span class="line"></span><br><span class="line">    public <span class="type">Student</span>(<span class="type">String</span> name, int age, int score) &#123;</span><br><span class="line">        <span class="keyword">super</span>(); <span class="comment">// 自动调用父类的构造方法</span></span><br><span class="line">        <span class="keyword">this</span>.score = score;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>但是，<code>Person</code>类并没有无参数的构造方法，因此，编译失败。</p>
<p>解决方法是调用<code>Person</code>类存在的某个构造方法。例如：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Student</span> <span class="keyword">extends</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> int score;</span><br><span class="line"></span><br><span class="line">    public <span class="type">Student</span>(<span class="type">String</span> name, int age, int score) &#123;</span><br><span class="line">        <span class="keyword">super</span>(name, age); <span class="comment">// 调用父类的构造方法Person(String, int)</span></span><br><span class="line">        <span class="keyword">this</span>.score = score;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这样就可以正常编译了！</p>
<p>因此我们得出结论：如果父类没有默认的构造方法，子类就必须显式调用<code>super()</code>并给出参数以便让编译器定位到父类的一个合适的构造方法。</p>
<p>这里还顺带引出了另一个问题：即子类<em>不会继承</em>任何父类的构造方法。子类默认的构造方法是编译器自动生成的，不是继承的。</p>
<h3 id="向上转型"><a href="#向上转型" class="headerlink" title="向上转型"></a>向上转型</h3><p>如果一个引用变量的类型是<code>Student</code>，那么它可以指向一个<code>Student</code>类型的实例：</p>
<figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">Student s</span> = new Student();</span><br></pre></td></tr></table></figure>

<p>如果一个引用类型的变量是<code>Person</code>，那么它可以指向一个<code>Person</code>类型的实例：</p>
<figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">Person p</span> = new Person();</span><br></pre></td></tr></table></figure>

<p>现在问题来了：如果<code>Student</code>是从<code>Person</code>继承下来的，那么，一个引用类型为<code>Person</code>的变量，能否指向<code>Student</code>类型的实例？</p>
<figure class="highlight haxe"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Person p = <span class="keyword">new</span> <span class="type">Student</span>(); <span class="comment">// ???</span></span><br></pre></td></tr></table></figure>

<p>测试一下就可以发现，这种指向是允许的！</p>
<p>这是因为<code>Student</code>继承自<code>Person</code>，因此，它拥有<code>Person</code>的全部功能。<code>Person</code>类型的变量，如果指向<code>Student</code>类型的实例，对它进行操作，是没有问题的！</p>
<p>这种把一个子类类型安全地变为父类类型的赋值，被称为向上转型（upcasting）。</p>
<p>向上转型实际上是把一个子类型安全地变为更加抽象的父类型：</p>
<figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Student s = new Student();</span><br><span class="line">Person p = s; <span class="regexp">//</span> upcasting, ok</span><br><span class="line">Object o1 = p; <span class="regexp">//</span> upcasting, ok</span><br><span class="line">Object o2 = s; <span class="regexp">//</span> upcasting, ok</span><br></pre></td></tr></table></figure>

<p>注意到继承树是<code>Student &gt; Person &gt; Object</code>，所以，可以把<code>Student</code>类型转型为<code>Person</code>，或者更高层次的<code>Object</code>。</p>
<h3 id="向下转型"><a href="#向下转型" class="headerlink" title="向下转型"></a>向下转型</h3><p>和向上转型相反，如果把一个父类类型强制转型为子类类型，就是向下转型（downcasting）。例如：</p>
<figure class="highlight haxe"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Person p1 = <span class="keyword">new</span> <span class="type">Student</span>(); <span class="comment">// upcasting, ok</span></span><br><span class="line">Person p2 = <span class="keyword">new</span> <span class="type">Person</span>();</span><br><span class="line">Student s1 = (Student) p1; <span class="comment">// ok</span></span><br><span class="line">Student s2 = (Student) p2; <span class="comment">// runtime error! ClassCastException!</span></span><br></pre></td></tr></table></figure>

<p>如果测试上面的代码，可以发现：</p>
<p><code>Person</code>类型<code>p1</code>实际指向<code>Student</code>实例，<code>Person</code>类型变量<code>p2</code>实际指向<code>Person</code>实例。在向下转型的时候，把<code>p1</code>转型为<code>Student</code>会成功，因为<code>p1</code>确实指向<code>Student</code>实例，把<code>p2</code>转型为<code>Student</code>会失败，因为<code>p2</code>的实际类型是<code>Person</code>，不能把父类变为子类，因为子类功能比父类多，多的功能无法凭空变出来。</p>
<p>因此，向下转型很可能会失败。失败的时候，Java虚拟机会报<code>ClassCastException</code>。</p>
<h3 id="区分继承和组合"><a href="#区分继承和组合" class="headerlink" title="区分继承和组合"></a>区分继承和组合</h3><p>在使用继承时，我们要注意逻辑一致性。</p>
<p>考察下面的<code>Book</code>类：</p>
<figure class="highlight nim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">class <span class="type">Book</span> &#123;</span><br><span class="line">    protected <span class="type">String</span> name;</span><br><span class="line">    public <span class="type">String</span> getName() <span class="meta">&#123;...&#125;</span></span><br><span class="line">    public <span class="built_in">void</span> setName(<span class="type">String</span> name) <span class="meta">&#123;...&#125;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这个<code>Book</code>类也有<code>name</code>字段，那么，我们能不能让<code>Student</code>继承自<code>Book</code>呢？</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Student</span> <span class="keyword">extends</span> <span class="title">Book</span> </span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> int score;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>显然，从逻辑上讲，这是不合理的，<code>Student</code>不应该从<code>Book</code>继承，而应该从<code>Person</code>继承。</p>
<p>究其原因，是因为<code>Student</code>是<code>Person</code>的一种，它们是is关系，而<code>Student</code>并不是<code>Book</code>。实际上<code>Student</code>和<code>Book</code>的关系是has关系。</p>
<p>具有has关系不应该使用继承，而是使用组合，即<code>Student</code>可以持有一个<code>Book</code>实例：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Student</span> <span class="keyword">extends</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> <span class="type">Book</span> book;</span><br><span class="line">    <span class="keyword">protected</span> int score;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>因此，继承是is关系，组合是has关系。</p>
<h3 id="重写"><a href="#重写" class="headerlink" title="重写"></a>重写</h3><p>在继承关系中，子类如果定义了一个与父类方法签名完全相同的方法，被称为覆写（Override）。</p>
<p>例如，在<code>Person</code>类中，我们定义了<code>run()</code>方法：</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> &#123;</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.<span class="built_in">println</span>(<span class="string">&quot;Person.run&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在子类<code>Student</code>中，覆写这个<code>run()</code>方法：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Student</span> <span class="keyword">extends</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    public void run() &#123;</span><br><span class="line">        <span class="type">System</span>.out.println(<span class="string">&quot;Student.run&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Override和Overload不同的是，如果方法签名如果不同，就是Overload，Overload方法是一个新方法；如果方法签名相同，并且返回值也相同，就是<code>Override</code>。</p>
<p><code>注意</code>：方法名相同，方法参数相同，但方法返回值不同，也是不同的方法。在Java程序中，出现这种情况，编译器会报错。</p>
<h1 id="（6）多态"><a href="#（6）多态" class="headerlink" title="（6）多态"></a>（6）多态</h1><p>多态是指，针对某个类型的方法调用，其真正执行的方法取决于运行时期实际类型的方法。例如：</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Person p = <span class="keyword">new</span> Student();</span><br><span class="line">p.<span class="built_in">run</span>(); <span class="comment">// 无法确定运行时究竟调用哪个run()方法</span></span><br></pre></td></tr></table></figure>

<p>有童鞋会问，从上面的代码一看就明白，肯定调用的是<code>Student</code>的<code>run()</code>方法啊。</p>
<p>但是，假设我们编写这样一个方法：</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">runTwice</span><span class="params">(Person p)</span> </span>&#123;</span><br><span class="line">    p.<span class="built_in">run</span>();</span><br><span class="line">    p.<span class="built_in">run</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>它传入的参数类型是<code>Person</code>，我们是无法知道传入的参数实际类型究竟是<code>Person</code>，还是<code>Student</code>，还是<code>Person</code>的其他子类，因此，也无法确定调用的是不是<code>Person</code>类定义的<code>run()</code>方法。</p>
<p>所以，多态的特性就是，运行期才能动态决定调用的子类方法。对某个类型调用某个方法，执行的实际方法可能是某个子类的覆写方法。这种不确定性的方法调用，究竟有什么作用？</p>
<p>我们还是来举栗子。</p>
<p>假设我们定义一种收入，需要给它报税，那么先定义一个<code>Income</code>类：</p>
<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="symbol">Income</span> &#123;</span><br><span class="line">    <span class="keyword">protected</span> <span class="built_in">double</span> income;</span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">double</span> getTax() &#123;</span><br><span class="line">        <span class="keyword">return</span> income * <span class="number">0.1</span>; <span class="comment">// 税率10%</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>对于工资收入，可以减去一个基数，那么我们可以从<code>Income</code>派生出<code>SalaryIncome</code>，并覆写<code>getTax()</code>：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Salary</span> <span class="keyword">extends</span> <span class="title">Income</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    public double getTax() &#123;</span><br><span class="line">        <span class="keyword">if</span> (income &lt;= <span class="number">5000</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> (income - <span class="number">5000</span>) * <span class="number">0.2</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如果你享受国务院特殊津贴，那么按照规定，可以全部免税：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">StateCouncilSpecialAllowance</span> <span class="keyword">extends</span> <span class="title">Income</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    public double getTax() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>现在，我们要编写一个报税的财务软件，对于一个人的所有收入进行报税，可以这么写：</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">totalTax</span><span class="params">(Income... incomes)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">double</span> total = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span> (Income income: incomes) &#123;</span><br><span class="line">        total = total + income.getTax();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> total;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>来试一下：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">void</span> <span class="function"><span class="title">main</span>(<span class="params"><span class="built_in">String</span>[] args</span>)</span> &#123;</span><br><span class="line">        <span class="comment">// 给一个有普通收入、工资收入和享受国务院特殊津贴的小伙伴算税:</span></span><br><span class="line">        Income[] incomes = <span class="keyword">new</span> Income[] &#123;</span><br><span class="line">            <span class="keyword">new</span> Income(<span class="number">3000</span>),</span><br><span class="line">            <span class="keyword">new</span> Salary(<span class="number">7500</span>),</span><br><span class="line">            <span class="keyword">new</span> StateCouncilSpecialAllowance(<span class="number">15000</span>)</span><br><span class="line">        &#125;;</span><br><span class="line">        System.out.println(totalTax(incomes));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> double <span class="function"><span class="title">totalTax</span>(<span class="params">Income... incomes</span>)</span> &#123;</span><br><span class="line">        double total = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (Income income: incomes) &#123;</span><br><span class="line">            total = total + income.getTax();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> total;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Income</span> </span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> double income;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="title">Income</span>(<span class="params">double income</span>)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.income = income;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> double <span class="function"><span class="title">getTax</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> income * <span class="number">0.1</span>; <span class="comment">// 税率10%</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Salary</span> <span class="keyword">extends</span> <span class="title">Income</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="title">Salary</span>(<span class="params">double income</span>)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(income);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> double <span class="function"><span class="title">getTax</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (income &lt;= <span class="number">5000</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> (income - <span class="number">5000</span>) * <span class="number">0.2</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">StateCouncilSpecialAllowance</span> <span class="keyword">extends</span> <span class="title">Income</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="title">StateCouncilSpecialAllowance</span>(<span class="params">double income</span>)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(income);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> double <span class="function"><span class="title">getTax</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>观察<code>totalTax()</code>方法：利用多态，<code>totalTax()</code>方法只需要和<code>Income</code>打交道，它完全不需要知道<code>Salary</code>和<code>StateCouncilSpecialAllowance</code>的存在，就可以正确计算出总的税。如果我们要新增一种稿费收入，只需要从<code>Income</code>派生，然后正确覆写<code>getTax()</code>方法就可以。把新的类型传入<code>totalTax()</code>，不需要修改任何代码。</p>
<p>可见，多态具有一个非常强大的功能，就是允许添加更多类型的子类实现功能扩展，却不需要修改基于父类的代码。</p>
<h3 id="覆写Object方法"><a href="#覆写Object方法" class="headerlink" title="覆写Object方法"></a>覆写Object方法</h3><p>因为所有的<code>class</code>最终都继承自<code>Object</code>，而<code>Object</code>定义了几个重要的方法：</p>
<ul>
<li><code>toString()</code>：把instance输出为<code>String</code>；</li>
<li><code>equals()</code>：判断两个instance是否逻辑相等；</li>
<li><code>hashCode()</code>：计算一个instance的哈希值。</li>
</ul>
<p>在必要的情况下，我们可以覆写<code>Object</code>的这几个方法。例如：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    ...</span><br><span class="line">    <span class="comment">// 显示更有意义的字符串:</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">toString</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Person:name=&quot;</span> + name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 比较是否相等:</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">boolean</span> <span class="function"><span class="title">equals</span>(<span class="params"><span class="built_in">Object</span> o</span>)</span> &#123;</span><br><span class="line">        <span class="comment">// 当且仅当o为Person类型:</span></span><br><span class="line">        <span class="keyword">if</span> (o <span class="keyword">instanceof</span> Person) &#123;</span><br><span class="line">            Person p = (Person) o;</span><br><span class="line">            <span class="comment">// 并且name字段相同时，返回true:</span></span><br><span class="line">            <span class="keyword">return</span> <span class="built_in">this</span>.name.equals(p.name);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 计算hash:</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> int <span class="function"><span class="title">hashCode</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.name.hashCode();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="调用super"><a href="#调用super" class="headerlink" title="调用super"></a>调用super</h3><p>在子类的覆写方法中，如果要调用父类的被覆写的方法，可以通过<code>super</code>来调用。例如：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> <span class="built_in">String</span> name;</span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">hello</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Hello, &quot;</span> + name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">Student <span class="keyword">extends</span> Person &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">hello</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="comment">// 调用父类的hello()方法:</span></span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">super</span>.hello() + <span class="string">&quot;!&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="final"><a href="#final" class="headerlink" title="final"></a>final</h3><p>继承可以允许子类覆写父类的方法。如果一个父类不允许子类对它的某个方法进行覆写，可以把该方法标记为<code>final</code>。用<code>final</code>修饰的方法不能被<code>Override</code>：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> <span class="built_in">String</span> name;</span><br><span class="line">    <span class="keyword">public</span> final <span class="built_in">String</span> <span class="function"><span class="title">hello</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Hello, &quot;</span> + name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">Student <span class="keyword">extends</span> Person &#123;</span><br><span class="line">    <span class="comment">// compile error: 不允许覆写</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">hello</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如果一个类不希望任何其他类继承自它，那么可以把这个类本身标记为<code>final</code>。用<code>final</code>修饰的类不能被继承：</p>
<figure class="highlight actionscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> String name;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// compile error: 不允许继承自Person</span></span><br><span class="line">Student <span class="keyword">extends</span> Person &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>对于一个类的实例字段，同样可以用<code>final</code>修饰。用<code>final</code>修饰的字段在初始化后不能被修改。例如：</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> &#123;</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">String</span> name = <span class="string">&quot;Unamed&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>对<code>final</code>字段重新赋值会报错：</p>
<figure class="highlight haxe"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Person p = <span class="keyword">new</span> <span class="type">Person</span>();</span><br><span class="line">p.name = <span class="string">&quot;New Name&quot;</span>; <span class="comment">// compile error!</span></span><br></pre></td></tr></table></figure>

<p>可以在构造方法中初始化final字段：</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> &#123;</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">String</span> name;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Person</span><span class="params">(<span class="keyword">String</span> name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这种方法更为常用，因为可以保证实例一旦创建，其<code>final</code>字段就不可修改。</p>
<h3 id="抽象类"><a href="#抽象类" class="headerlink" title="抽象类"></a>抽象类</h3><p>由于多态的存在，每个子类都可以覆写父类的方法，例如：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    public void run() &#123; … &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Student</span> <span class="keyword">extends</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    public void run() &#123; … &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Teacher</span> <span class="keyword">extends</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    public void run() &#123; … &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>从<code>Person</code>类派生的<code>Student</code>和<code>Teacher</code>都可以覆写<code>run()</code>方法。</p>
<p>如果父类<code>Person</code>的<code>run()</code>方法没有实际意义，能否去掉方法的执行语句？</p>
<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="symbol">Person</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">void</span> run(); <span class="comment">// Compile Error!</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>答案是不行，会导致编译错误，因为定义方法的时候，必须实现方法的语句。</p>
<p>能不能去掉父类的<code>run()</code>方法？</p>
<p>答案还是不行，因为去掉父类的<code>run()</code>方法，就失去了多态的特性。例如，<code>runTwice()</code>就无法编译：</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">runTwice</span><span class="params">(Person p)</span> </span>&#123;</span><br><span class="line">    p.<span class="built_in">run</span>(); <span class="comment">// Person没有run()方法，会导致编译错误</span></span><br><span class="line">    p.<span class="built_in">run</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如果父类的方法本身不需要实现任何功能，仅仅是为了定义方法签名，目的是让子类去覆写它，那么，可以把父类的方法声明为抽象方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>把一个方法声明为<code>abstract</code>，表示它是一个抽象方法，本身没有实现任何方法语句。因为这个抽象方法本身是无法执行的，所以，<code>Person</code>类也无法被实例化。编译器会告诉我们，无法编译<code>Person</code>类，因为它包含抽象方法。</p>
<p>必须把<code>Person</code>类本身也声明为<code>abstract</code>，才能正确编译它：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="抽象类-1"><a href="#抽象类-1" class="headerlink" title="抽象类"></a>抽象类</h3><p>如果一个<code>class</code>定义了方法，但没有具体执行代码，这个方法就是抽象方法，抽象方法用<code>abstract</code>修饰。</p>
<p>因为无法执行抽象方法，因此这个类也必须申明为抽象类（abstract class）。</p>
<p>使用<code>abstract</code>修饰的类就是抽象类。我们无法实例化一个抽象类：</p>
<figure class="highlight haxe"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Person p = <span class="keyword">new</span> <span class="type">Person</span>(); <span class="comment">// 编译错误</span></span><br></pre></td></tr></table></figure>

<p>无法实例化的抽象类有什么用？</p>
<p>因为抽象类本身被设计成只能用于被继承，因此，抽象类可以强迫子类实现其定义的抽象方法，否则编译会报错。因此，抽象方法实际上相当于定义了“规范”。</p>
<p>例如，<code>Person</code>类定义了抽象方法<code>run()</code>，那么，在实现子类<code>Student</code>的时候，就必须覆写<code>run()</code>方法：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">void</span> <span class="function"><span class="title">main</span>(<span class="params"><span class="built_in">String</span>[] args</span>)</span> &#123;</span><br><span class="line">        Person p = <span class="keyword">new</span> Student();</span><br><span class="line">        p.run();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="built_in">void</span> run();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Student</span> <span class="keyword">extends</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">void</span> <span class="function"><span class="title">run</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;Student.run&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//运行结果</span></span><br><span class="line">Student.run</span><br></pre></td></tr></table></figure>

<h3 id="面向抽象编程"><a href="#面向抽象编程" class="headerlink" title="面向抽象编程"></a>面向抽象编程</h3><p>当我们定义了抽象类<code>Person</code>，以及具体的<code>Student</code>、<code>Teacher</code>子类的时候，我们可以通过抽象类<code>Person</code>类型去引用具体的子类的实例：</p>
<figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">Person s</span> = new Student();</span><br><span class="line"><span class="attribute">Person t</span> = new Teacher();</span><br></pre></td></tr></table></figure>

<p>这种引用抽象类的好处在于，我们对其进行方法调用，并不关心<code>Person</code>类型变量的具体子类型：</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 不关心Person变量的具体子类型:</span></span><br><span class="line">s.<span class="built_in">run</span>();</span><br><span class="line">t.<span class="built_in">run</span>();</span><br></pre></td></tr></table></figure>

<p>同样的代码，如果引用的是一个新的子类，我们仍然不关心具体类型：</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 同样不关心新的子类是如何实现run()方法的：</span></span><br><span class="line">Person e = <span class="keyword">new</span> Employee();</span><br><span class="line">e.<span class="built_in">run</span>();</span><br></pre></td></tr></table></figure>

<p>这种尽量引用高层类型，避免引用实际子类型的方式，称之为面向抽象编程。</p>
<p>面向抽象编程的本质就是：</p>
<ul>
<li>上层代码只定义规范（例如：<code>abstract class Person</code>）；</li>
<li>不需要子类就可以实现业务逻辑（正常编译）；</li>
<li>具体的业务逻辑由不同的子类实现，调用者并不关心。</li>
</ul>
<h1 id="（7）接口"><a href="#（7）接口" class="headerlink" title="（7）接口"></a>（7）接口</h1><p>在抽象类中，抽象方法本质上是定义接口规范：即规定高层类的接口，从而保证所有子类都有相同的接口实现，这样，多态就能发挥出威力。</p>
<p>如果一个抽象类没有字段，所有方法全部都是抽象方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> String <span class="title">getName</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>就可以把该抽象类改写为接口：<code>interface</code>。</p>
<p>在Java中，使用<code>interface</code>可以声明一个接口：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">run</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function">String <span class="title">getName</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>所谓<code>interface</code>，就是比抽象类还要抽象的纯抽象接口，因为它连字段都不能有。因为接口定义的所有方法默认都是<code>public abstract</code>的，所以这两个修饰符不需要写出来（写不写效果都一样）。</p>
<p>当一个具体的<code>class</code>去实现一个<code>interface</code>时，需要使用<code>implements</code>关键字。举个例子：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Student</span> <span class="title">implements</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="built_in">String</span> name;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="title">Student</span>(<span class="params"><span class="built_in">String</span> name</span>)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">void</span> <span class="function"><span class="title">run</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        System.out.println(<span class="built_in">this</span>.name + <span class="string">&quot; run&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">getName</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们知道，在Java中，一个类只能继承自另一个类，不能从多个类继承。但是，一个类可以实现多个<code>interface</code>，例如：</p>
<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="symbol">Student</span> <span class="symbol">implements</span> <span class="symbol">Person, <span class="symbol">Hello</span></span> &#123; <span class="comment">// 实现了两个interface</span></span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="术语"><a href="#术语" class="headerlink" title="术语"></a>术语</h3><p>注意区分术语：</p>
<p>Java的接口特指<code>interface</code>的定义，表示一个接口类型和一组方法签名，而编程接口泛指接口规范，如方法签名，数据格式，网络协议等。</p>
<p>抽象类和接口的对比如下：</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="left">abstract class</th>
<th align="left">interface</th>
</tr>
</thead>
<tbody><tr>
<td align="left">继承</td>
<td align="left">只能extends一个class</td>
<td align="left">可以implements多个interface</td>
</tr>
<tr>
<td align="left">字段</td>
<td align="left">可以定义实例字段</td>
<td align="left">不能定义实例字段</td>
</tr>
<tr>
<td align="left">抽象方法</td>
<td align="left">可以定义抽象方法</td>
<td align="left">可以定义抽象方法</td>
</tr>
<tr>
<td align="left">非抽象方法</td>
<td align="left">可以定义非抽象方法</td>
<td align="left">可以定义default方法</td>
</tr>
</tbody></table>
<h3 id="接口继承"><a href="#接口继承" class="headerlink" title="接口继承"></a>接口继承</h3><p>一个<code>interface</code>可以继承自另一个<code>interface</code>。<code>interface</code>继承自<code>interface</code>使用<code>extends</code>，它相当于扩展了接口的方法。例如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Hello</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">hello</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Person</span> <span class="keyword">extends</span> <span class="title">Hello</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">run</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function">String <span class="title">getName</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>此时，<code>Person</code>接口继承自<code>Hello</code>接口，因此，<code>Person</code>接口现在实际上有3个抽象方法签名，其中一个来自继承的<code>Hello</code>接口。</p>
<h3 id="继承关系"><a href="#继承关系" class="headerlink" title="继承关系"></a>继承关系</h3><p>合理设计<code>interface</code>和<code>abstract class</code>的继承关系，可以充分复用代码。一般来说，公共逻辑适合放在<code>abstract class</code>中，具体逻辑放到各个子类，而接口层次代表抽象程度。可以参考Java的集合类定义的一组接口、抽象类以及具体子类的继承关系：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">┌───────────────┐</span><br><span class="line">│   Iterable    │</span><br><span class="line">└───────────────┘</span><br><span class="line">        ▲                ┌───────────────────┐</span><br><span class="line">        │                │      Object       │</span><br><span class="line">┌───────────────┐        └───────────────────┘</span><br><span class="line">│  Collection   │                  ▲</span><br><span class="line">└───────────────┘                  │</span><br><span class="line">        ▲     ▲          ┌───────────────────┐</span><br><span class="line">        │     └──────────│AbstractCollection │</span><br><span class="line">┌───────────────┐        └───────────────────┘</span><br><span class="line">│     List      │                  ▲</span><br><span class="line">└───────────────┘                  │</span><br><span class="line">              ▲          ┌───────────────────┐</span><br><span class="line">              └──────────│   AbstractList    │</span><br><span class="line">                         └───────────────────┘</span><br><span class="line">                                ▲     ▲</span><br><span class="line">                                │     │</span><br><span class="line">                                │     │</span><br><span class="line">                     ┌────────────┐ ┌────────────┐</span><br><span class="line">                     │ ArrayList  │ │ LinkedList │</span><br><span class="line">                     └────────────┘ └────────────┘</span><br></pre></td></tr></table></figure>

<p>在使用的时候，实例化的对象永远只能是某个具体的子类，但总是通过接口去引用它，因为接口比抽象类更抽象：</p>
<figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">List list = new ArrayList(); <span class="regexp">//</span> 用List接口引用具体子类的实例</span><br><span class="line">Collection coll = list; <span class="regexp">//</span> 向上转型为Collection接口</span><br><span class="line">Iterable it = coll; <span class="regexp">//</span> 向上转型为Iterable接口</span><br></pre></td></tr></table></figure>

<h3 id="default方法"><a href="#default方法" class="headerlink" title="default方法"></a>default方法</h3><p>在接口中，可以定义<code>default</code>方法。例如，把<code>Person</code>接口的<code>run()</code>方法改为<code>default</code>方法：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Demo</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">void</span> <span class="function"><span class="title">main</span>(<span class="params"><span class="built_in">String</span>[] args</span>)</span> &#123;</span><br><span class="line">        Person p = <span class="keyword">new</span> Student(<span class="string">&quot;Xiao Ming&quot;</span>);</span><br><span class="line">        p.run();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> Person &#123;</span><br><span class="line">    <span class="built_in">String</span> getName();</span><br><span class="line">    <span class="keyword">default</span> <span class="built_in">void</span> <span class="function"><span class="title">run</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        System.out.println(getName() + <span class="string">&quot; run&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Student</span> <span class="title">implements</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="built_in">String</span> name;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="title">Student</span>(<span class="params"><span class="built_in">String</span> name</span>)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">getName</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>实现类可以不必覆写<code>default</code>方法。<code>default</code>方法的目的是，当我们需要给接口新增一个方法时，会涉及到修改全部子类。如果新增的是<code>default</code>方法，那么子类就不必全部修改，只需要在需要覆写的地方去覆写新增方法。</p>
<p><code>default</code>方法和抽象类的普通方法是有所不同的。因为<code>interface</code>没有字段，<code>default</code>方法无法访问字段，而抽象类的普通方法可以访问实例字段。</p>
<h1 id="（8）静态字段和静态方法"><a href="#（8）静态字段和静态方法" class="headerlink" title="（8）静态字段和静态方法"></a>（8）静态字段和静态方法</h1><p>在一个<code>class</code>中定义的字段，我们称之为实例字段。实例字段的特点是，每个实例都有独立的字段，各个实例的同名字段互不影响。</p>
<p>还有一种字段，是用    <code>static</code>修饰的字段，称为静态字段：<code>static field</code>。</p>
<p>实例字段在每个实例中都有自己的一个独立“空间”，但是静态字段只有一个共享“空间”，所有实例都会共享该字段。举个例子：</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> &#123;</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">String</span> name;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> age;</span><br><span class="line">    <span class="comment">// 定义静态字段number:</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> number;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>对于静态字段，无论修改哪个实例的静态字段，效果都是一样的：所有实例的静态字段都被修改了，原因是静态字段并不属于实例：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">        ┌──────────────────┐</span><br><span class="line">Fox  ──&gt;│Person instance   │</span><br><span class="line">        ├──────────────────┤</span><br><span class="line">        │name &#x3D; &quot;Fox&quot;      │</span><br><span class="line">        │age &#x3D; 12          │</span><br><span class="line">        │number ───────────┼──┐    ┌─────────────┐</span><br><span class="line">        └──────────────────┘  │    │Person class │</span><br><span class="line">                              │    ├─────────────┤</span><br><span class="line">                              ├───&gt;│number &#x3D; 99  │</span><br><span class="line">        ┌──────────────────┐  │    └─────────────┘</span><br><span class="line">zjh  ──&gt;│Person instance   │  │</span><br><span class="line">        ├──────────────────┤  │</span><br><span class="line">        │name &#x3D; &quot;zjh&quot;      │  │</span><br><span class="line">        │age &#x3D; 19          │  │</span><br><span class="line">        │number ───────────┼──┘</span><br><span class="line">        └──────────────────┘</span><br></pre></td></tr></table></figure>

<p>虽然实例可以访问静态字段，但是它们指向的其实都是<code>Person class</code>的静态字段。所以，所有实例共享一个静态字段。</p>
<p>因此，不推荐用<code>实例变量.静态字段</code>去访问静态字段，因为在Java程序中，实例对象并没有静态字段。在代码中，实例对象能访问静态字段只是因为编译器可以根据实例类型自动转换为<code>类名.静态字段</code>来访问静态对象。</p>
<p>推荐用类名来访问静态字段。可以把静态字段理解为描述<code>class</code>本身的字段（非实例字段）。对于上面的代码，更好的写法是：</p>
<figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="module-access"><span class="module"><span class="identifier">Person</span>.</span></span>number = <span class="number">99</span>;</span><br><span class="line"><span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(<span class="module-access"><span class="module"><span class="identifier">Person</span>.</span></span>number);</span><br></pre></td></tr></table></figure>

<h3 id="静态方法"><a href="#静态方法" class="headerlink" title="静态方法"></a>静态方法</h3><p>有静态字段，就有静态方法。用<code>static</code>修饰的方法称为静态方法。</p>
<p>调用实例方法必须通过一个实例变量，而调用静态方法则不需要实例变量，通过类名就可以调用。静态方法类似其它编程语言的函数。例如：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">void</span> <span class="function"><span class="title">main</span>(<span class="params"><span class="built_in">String</span>[] args</span>)</span> &#123;</span><br><span class="line">        Person.setNumber(<span class="number">99</span>);</span><br><span class="line">        System.out.println(Person.number);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> int <span class="built_in">number</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">void</span> <span class="function"><span class="title">setNumber</span>(<span class="params">int value</span>)</span> &#123;</span><br><span class="line">        <span class="built_in">number</span> = value;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//结果：99</span></span><br></pre></td></tr></table></figure>

<p>因为静态方法属于<code>class</code>而不属于实例，因此，静态方法内部，无法访问<code>this</code>变量，也无法访问实例字段，它只能访问静态字段。</p>
<p>通过实例变量也可以调用静态方法，但这只是编译器自动帮我们把实例改写成类名而已。</p>
<p>通常情况下，通过实例变量访问静态字段和静态方法，会得到一个编译警告。</p>
<p>静态方法经常用于工具类。例如：</p>
<ul>
<li>Arrays.sort()</li>
<li>Math.random()</li>
</ul>
<p>静态方法也经常用于辅助方法。注意到Java程序的入口<code>main()</code>也是静态方法。</p>
<h3 id="接口的静态字段"><a href="#接口的静态字段" class="headerlink" title="接口的静态字段"></a>接口的静态字段</h3><p>因为<code>interface</code>是一个纯抽象类，所以它不能定义实例字段。但是，<code>interface</code>是可以有静态字段的，并且静态字段必须为<code>final</code>类型：</p>
<figure class="highlight axapta"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="built_in">int</span> MALE = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="built_in">int</span> FEMALE = <span class="number">2</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>实际上，因为<code>interface</code>的字段只能是<code>public static final</code>类型，所以我们可以把这些修饰符都去掉，上述代码可以简写为：</p>
<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="symbol">Person</span> &#123;</span><br><span class="line">    <span class="comment">// 编译器会自动加上public statc final:</span></span><br><span class="line">    <span class="built_in">int</span> MALE = <span class="number">1</span>;</span><br><span class="line">    <span class="built_in">int</span> FEMALE = <span class="number">2</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编译器会自动把该字段变为<code>public static final</code>类型。</p>
<h2 id="包"><a href="#包" class="headerlink" title="包"></a>包</h2><p>包可以将java类放在在里面，避免类名重复。也方便了后期项目的维护。</p>
<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">package com; <span class="comment">// 申明包名com</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="symbol">Person</span> &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="包的作用域"><a href="#包的作用域" class="headerlink" title="包的作用域"></a>包的作用域</h3><p>位于同一个包的类，可以访问包作用域的字段和方法。不用<code>public</code>、<code>protected</code>、<code>private</code>修饰的字段和方法就是包作用域。</p>
<h3 id="import"><a href="#import" class="headerlink" title="import"></a>import</h3><p>在一个<code>class</code>中，我们总会引用其他包的<code>class</code>。比如我要调用一个在其他包的某个类，就可以：</p>
<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Xxx<span class="comment">//包名</span></span><br></pre></td></tr></table></figure>

<p><code>注意：</code></p>
<ul>
<li>Java内建的<code>package</code>机制是为了避免<code>class</code>命名冲突；</li>
<li>JDK的核心类使用<code>java.lang</code>包，编译器会自动导入；</li>
<li>JDK的其它常用类定义在<code>java.util.*</code>，<code>java.math.*</code>，<code>java.text.*</code>，……；</li>
</ul>
<h2 id="作用域"><a href="#作用域" class="headerlink" title="作用域"></a>作用域</h2><p>在Java中，我们经常看到<code>public</code>、<code>protected</code>、<code>private</code>这些修饰符。在Java中，这些修饰符可以用来限定访问作用域。</p>
<h3 id="public"><a href="#public" class="headerlink" title="public"></a>public</h3><p>定义为<code>public</code>的<code>class</code>、<code>interface</code>可以被其他任何类访问：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> abc;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Hello</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">hi</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上面的<code>Hello</code>是<code>public</code>，因此，可以被其他包的类访问：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> xyz;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">foo</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">// Main可以访问Hello</span></span><br><span class="line">        Hello h = <span class="keyword">new</span> Hello();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>定义为<code>public</code>的<code>field</code>、<code>method</code>可以被其他类访问，前提是首先有访问<code>class</code>的权限：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> abc;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Hello</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">hi</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上面的<code>hi()</code>方法是<code>public</code>，可以被其他类调用，前提是首先要能访问<code>Hello</code>类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> xyz;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">foo</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        Hello h = <span class="keyword">new</span> Hello();</span><br><span class="line">        h.hi();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="private"><a href="#private" class="headerlink" title="private"></a>private</h3><p>定义为<code>private</code>的<code>field</code>、<code>method</code>无法被其他类访问：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">package abc;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Hello</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 不能被其他类调用:</span></span><br><span class="line">    <span class="keyword">private</span> <span class="built_in">void</span> <span class="function"><span class="title">hi</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">void</span> <span class="function"><span class="title">hello</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.hi();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>实际上，确切地说，<code>private</code>访问权限被限定在<code>class</code>的内部，而且与方法声明顺序<em>无关</em>。推荐把<code>private</code>方法放到后面，因为<code>public</code>方法定义了类对外提供的功能，阅读代码的时候，应该先关注<code>public</code>方法：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">package abc;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Hello</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">void</span> <span class="function"><span class="title">hello</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.hi();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="built_in">void</span> <span class="function"><span class="title">hi</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>由于Java支持嵌套类，如果一个类内部还定义了嵌套类，那么，嵌套类拥有访问<code>private</code>的权限：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">void</span> <span class="function"><span class="title">main</span>(<span class="params"><span class="built_in">String</span>[] args</span>)</span> &#123;</span><br><span class="line">        Inner i = <span class="keyword">new</span> Inner();</span><br><span class="line">        i.hi();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// private方法:</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="built_in">void</span> <span class="function"><span class="title">hello</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;private hello!&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 静态内部类:</span></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Inner</span> </span>&#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="built_in">void</span> <span class="function"><span class="title">hi</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">            Main.hello();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//结果：private hello!</span></span><br></pre></td></tr></table></figure>

<p>定义在一个<code>class</code>内部的<code>class</code>称为嵌套类（<code>nested class</code>），Java支持好几种嵌套类。</p>
<h3 id="protected-1"><a href="#protected-1" class="headerlink" title="protected"></a>protected</h3><p><code>protected</code>作用于继承关系。定义为<code>protected</code>的字段和方法可以被子类访问，以及子类的子类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> abc;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Hello</span> </span>&#123;</span><br><span class="line">    <span class="comment">// protected方法:</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">hi</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上面的<code>protected</code>方法可以被继承的类访问：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> xyz;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Main</span> <span class="keyword">extends</span> <span class="title">Hello</span> </span>&#123;</span><br><span class="line">    void foo() &#123;</span><br><span class="line">        <span class="comment">// 可以访问protected方法:</span></span><br><span class="line">        hi();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="package"><a href="#package" class="headerlink" title="package"></a>package</h3><p>最后，包作用域是指一个类允许访问同一个<code>package</code>的没有<code>public</code>、<code>private</code>修饰的<code>class</code>，以及没有<code>public</code>、<code>protected</code>、<code>private</code>修饰的字段和方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> abc;</span><br><span class="line"><span class="comment">// package权限的类:</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Hello</span> </span>&#123;</span><br><span class="line">    <span class="comment">// package权限的方法:</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">hi</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>只要在同一个包，就可以访问<code>package</code>权限的<code>class</code>、<code>field</code>和<code>method</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> abc;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">foo</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 可以访问package权限的类:</span></span><br><span class="line">        Hello h = <span class="keyword">new</span> Hello();</span><br><span class="line">        <span class="comment">// 可以调用package权限的方法:</span></span><br><span class="line">        h.hi();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>注意，包名必须完全一致，包没有父子关系，<code>com.apache</code>和<code>com.apache.abc</code>是不同的包。</p>
<h3 id="局部变量"><a href="#局部变量" class="headerlink" title="局部变量"></a>局部变量</h3><p>在方法内部定义的变量称为局部变量，局部变量作用域从变量声明处开始到对应的块结束。方法参数也是局部变量。</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">package abc;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Hello</span> &#123;</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">hi</span><span class="params">(<span class="keyword">String</span> name)</span> </span>&#123; <span class="comment">// ①</span></span><br><span class="line">        <span class="keyword">String</span> s = name.toLowerCase(); <span class="comment">// ②</span></span><br><span class="line">        <span class="keyword">int</span> len = s.length(); <span class="comment">// ③</span></span><br><span class="line">        <span class="keyword">if</span> (len &lt; <span class="number">10</span>) &#123; <span class="comment">// ④</span></span><br><span class="line">            <span class="keyword">int</span> p = <span class="number">10</span> - len; <span class="comment">// ⑤</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i=<span class="number">0</span>; i&lt;<span class="number">10</span>; i++) &#123; <span class="comment">// ⑥</span></span><br><span class="line">                System.out.<span class="built_in">println</span>(); <span class="comment">// ⑦</span></span><br><span class="line">            &#125; <span class="comment">// ⑧</span></span><br><span class="line">        &#125; <span class="comment">// ⑨</span></span><br><span class="line">    &#125; <span class="comment">// ⑩</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们观察上面的<code>hi()</code>方法代码：</p>
<ul>
<li>方法参数name是局部变量，它的作用域是整个方法，即①～⑩；</li>
<li>变量s的作用域是定义处到方法结束，即②～⑩；</li>
<li>变量len的作用域是定义处到方法结束，即③～⑩；</li>
<li>变量p的作用域是定义处到if块结束，即⑤～⑨；</li>
<li>变量i的作用域是for循环，即⑥～⑧。</li>
</ul>
<p>使用局部变量时，应该尽可能把局部变量的作用域缩小，尽可能延后声明局部变量。</p>
<h3 id="final-1"><a href="#final-1" class="headerlink" title="final"></a>final</h3><p>Java还提供了一个<code>final</code>修饰符。<code>final</code>与访问权限不冲突，它有很多作用。</p>
<p>用<code>final</code>修饰<code>class</code>可以阻止被继承：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> abc;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 无法被继承:</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">Hello</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> n = <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">hi</span><span class="params">(<span class="keyword">int</span> t)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">long</span> i = t;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>用<code>final</code>修饰<code>method</code>可以阻止被子类覆写：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> abc;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Hello</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 无法被覆写:</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">hi</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>用<code>final</code>修饰<code>field</code>可以阻止被重新赋值：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> abc;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Hello</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> n = <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">hi</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.n = <span class="number">1</span>; <span class="comment">// error!</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>用<code>final</code>修饰局部变量可以阻止被重新赋值：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> abc;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Hello</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">hi</span><span class="params">(<span class="keyword">final</span> <span class="keyword">int</span> t)</span> </span>&#123;</span><br><span class="line">        t = <span class="number">1</span>; <span class="comment">// error!</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><del>md，累死我了呼，码了几天哈哈哈。</del></p>
<p>作者：<em>zjh</em></p>
 
      <!-- reward -->
      
      <div id="reword-out">
        <div id="reward-btn">
          打赏
        </div>
      </div>
      
    </div>
    

    <!-- copyright -->
    
    <div class="declare">
      <ul class="post-copyright">
        <li>
          <i class="ri-copyright-line"></i>
          <strong>版权声明： </strong>
          
          本网站所有文章除特别声明外，著作权归作者所有。转载请注明出处！
          
        </li>
      </ul>
    </div>
    
    <footer class="article-footer">
       
<div class="share-btn">
      <span class="share-sns share-outer">
        <i class="ri-share-forward-line"></i>
        分享
      </span>
      <div class="share-wrap">
        <i class="arrow"></i>
        <div class="share-icons">
          
          <a class="weibo share-sns" href="javascript:;" data-type="weibo">
            <i class="ri-weibo-fill"></i>
          </a>
          <a class="weixin share-sns wxFab" href="javascript:;" data-type="weixin">
            <i class="ri-wechat-fill"></i>
          </a>
          <a class="qq share-sns" href="javascript:;" data-type="qq">
            <i class="ri-qq-fill"></i>
          </a>
          <a class="douban share-sns" href="javascript:;" data-type="douban">
            <i class="ri-douban-line"></i>
          </a>
          <!-- <a class="qzone share-sns" href="javascript:;" data-type="qzone">
            <i class="icon icon-qzone"></i>
          </a> -->
          
          <a class="facebook share-sns" href="javascript:;" data-type="facebook">
            <i class="ri-facebook-circle-fill"></i>
          </a>
          <a class="twitter share-sns" href="javascript:;" data-type="twitter">
            <i class="ri-twitter-fill"></i>
          </a>
          <a class="google share-sns" href="javascript:;" data-type="google">
            <i class="ri-google-fill"></i>
          </a>
        </div>
      </div>
</div>

<div class="wx-share-modal">
    <a class="modal-close" href="javascript:;"><i class="ri-close-circle-line"></i></a>
    <p>扫一扫，分享到微信</p>
    <div class="wx-qrcode">
      <img src="//api.qrserver.com/v1/create-qr-code/?size=150x150&data=https://cxq21.gitee.io/posts/9d9ad23f.html" alt="微信分享二维码">
    </div>
</div>

<div id="share-mask"></div>  
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/JAVA%E7%AC%94%E8%AE%B0/" rel="tag">JAVA笔记</a></li></ul>

    </footer>
  </div>

   
  <nav class="article-nav">
    
      <a href="/posts/3dc898ff.html" class="article-nav-link">
        <strong class="article-nav-caption">上一篇</strong>
        <div class="article-nav-title">
          
            加入拾柒工作室
          
        </div>
      </a>
    
    
      <a href="/posts/3731d3f9.html" class="article-nav-link">
        <strong class="article-nav-caption">下一篇</strong>
        <div class="article-nav-title">WebGL流体效果</div>
      </a>
    
  </nav>

  
      
<!-- minivaline评论 -->
<div id="mvcomments-box">
  <div id="mvcomments"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/minivaline@3/dist/MiniValine.min.js"></script>
<script>
    new MiniValine({
        el: '#mvcomments',
        appId: 'lGCocPMCSUz2tL4FcKDvFCG3-gzGzoHsz',
        appKey: 'VheJztjyMzs24xKQPGGI1bmh',
        mode: 'xCss',
        placeholder: '评论的时候建议填上您的邮箱，可以第一时间收到我的回复喔',
        pathname: window.location.pathname,
        lang: '',
        adminEmailMd5: '69b690b67d0fb9dba8ab2de5db6dd353',
        tagMeta: ["LIEFox站长", "小伙伴", "来将可留姓名"],
        master: ["69b690b67d0fb9dba8ab2de5db6dd353"],
        friends: ["1f7c8b18fb7bbe18fbaf97309de2c0ac", "e5aec373ad8a0dce7abdbe4e6585a8ba"],
        math: true,
        md: true,
        enableQQ: true,
        NoRecordIP: true,
        visitor: false,
        maxNest: 6,
        pageSize: 6,
        serverURLs: '',
        emoticonUrl: ["https://cdn.jsdelivr.net/npm/alus@latest", "https://cdn.jsdelivr.net/gh/MiniValine/qq@latest", "https://cdn.jsdelivr.net/gh/MiniValine/Bilibilis@latest", "https://cdn.jsdelivr.net/gh/MiniValine/tieba@latest", "https://cdn.jsdelivr.net/gh/MiniValine/twemoji@latest", "https://cdn.jsdelivr.net/gh/MiniValine/weibo@latest"],
    });
  const infoEle = document.querySelector('#mvcomments .info');
  if (infoEle && infoEle.childNodes && infoEle.childNodes.length > 0) {
      infoEle.childNodes.forEach(function (item) {
          item.parentNode.removeChild(item);
      });
  }
</script>
<style>
	#mvcomments-box {
	padding: 5px 30px;
	}

	@media screen and (max-width: 800px) {
	#mvcomments-box {
	  padding: 5px 0px;
	}
	}

	.v .vlist .vcard .vh {
	padding-right: 20px;
	}

	.v .vlist .vcard {
	padding-left: 10px;
	}
	
	.darkmode .commentTrigger{
		background-color: #403e3e !important;
	  }
	.darkmode .MiniValine .vpage .more{
		background: #21232F
	}
	.darkmode img{
		  filter: brightness(30%)
	}
	.darkmode .MiniValine .vlist .vcard .vcomment-body .text-wrapper .vcomment.expand:before{
		background: linear-gradient(180deg, rgba(246,246,246,0), rgba(0,0,0,0.9))
	}
	.darkmode .MiniValine .vlist .vcard .vcomment-body .text-wrapper .vcomment.expand:after{
		background: rgba(0,0,0,0.9)
	}
	.darkmode .MiniValine .vlist .vcard .vcomment-body .text-wrapper .vcomment pre{
		background: #282c34
		border: 1px solid #282c34
	}
	.darkmode .MiniValine .vinputs-area .textarea-wrapper textarea{
		color: #000;
	}
	.darkmode .MiniValine .vinputs-area .auth-section .input-wrapper input{
		color: #000;
	}
	.darkmode .MiniValine .info .col .count{
		color: #000;
	}
	.darkmode .MiniValine .vinputs-area .vextra-area .vsmile-icons{
		background: transparent;
	}
</style>

 
</article>

</section>
      <footer class="footer">
  <div class="outer">
<!-- 运行天数 -->
    <ul>
        <li><span id="runtime_span"></span></li>
    </ul>

<script type="text/javascript">            
    function show_runtime() {
        window.setTimeout("show_runtime()", 1000);
        X = new Date("11/27/2020 17:17:17");
        Y = new Date();
        T = (Y.getTime() - X.getTime());
        M = 24 * 60 * 60 * 1000;
        a = T / M;
        A = Math.floor(a);
        b = (a - A) * 24;
        B = Math.floor(b);
        c = (b - B) * 60;
        C = Math.floor((b - B) * 60);
        D = Math.floor((c - C) * 60);
        runtime_span.innerHTML = "LIEFox逃脱猎人的第" + A + "天" + B + "小时" + C + "分" + D + "秒"
    }
    show_runtime();
</script>

    <ul>
      <li>
        Copyrights &copy;
        2020-2023
        <i class="ri-heart-fill heart_icon"></i> 拾柒工作室
      </li>
    </ul>


    <ul>
      <li>
        
      </li>
    </ul>
    <ul>
      <li>
        
        
        <span>
  <span><i class="ri-user-3-fill"></i>访问人数:<span id="busuanzi_value_site_uv"></span></s>
  <span class="division">|</span>
  <span><i class="ri-eye-fill"></i>浏览次数:<span id="busuanzi_value_page_pv"></span></span>
</span>
        
      </li>
    </ul>
    <ul>
      
    </ul>
    <ul>
      
    </ul>
    <ul>
      <li>
        <!-- cnzz统计 -->
        
        <script type="text/javascript" src='https://s9.cnzz.com/z_stat.php?id=1279472270&amp;web_id=1279472270'></script>
        
      </li>
    </ul>
  </div>
</footer>
      <div class="float_btns">
        <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>

<div class="todark" id="todark">
  <i class="ri-moon-line"></i>
</div>

      </div>
    </main>
    <aside class="sidebar on">
      <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/"><img src="/images/LIEFox.png" alt="LIEFox"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/archives">时间线</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/categories">分类</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags">标签</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/friends">友链</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/dplayer">视频</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/update">更新日志</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/about">关于LIEFox</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="搜索">
        <i class="ri-search-line"></i>
      </a>
      
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
    </aside>
    <script>
      if (window.matchMedia("(max-width: 768px)").matches) {
        document.querySelector('.content').classList.remove('on');
        document.querySelector('.sidebar').classList.remove('on');
      }
    </script>
    <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>感谢金主~</p>
  <div class="reward-box">
    
    
    <div class="reward-item">
      <img class="reward-img" src="/images/wechat.jpg">
      <span class="reward-type">微信</span>
    </div>
    
  </div>
</div>
    
<script src="/js/jquery-2.0.3.min.js"></script>


<script src="/js/lazyload.min.js"></script>

<!-- Tocbot -->


<script src="/js/tocbot.min.js"></script>

<script>
  tocbot.init({
    tocSelector: '.tocbot',
    contentSelector: '.article-entry',
    headingSelector: 'h1, h2, h3, h4, h5, h6',
    hasInnerContainers: true,
    scrollSmooth: true,
    scrollContainer: 'main',
    positionFixedSelector: '.tocbot',
    positionFixedClass: 'is-position-fixed',
    fixedSidebarOffset: 'auto'
  });
</script>

<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css">
<script src="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/js/jquery.justifiedGallery.min.js"></script>

<script src="/dist/main.js"></script>

<!-- ImageViewer -->

<!-- MathJax -->

<!-- Katex -->

<!-- busuanzi  -->


<script src="/js/busuanzi-2.3.pure.min.js"></script>


<!-- ClickLove -->

<!-- ClickBoom1 -->

<!-- ClickBoom2 -->


<script src="/js/clickBoom2.js"></script>


<!-- CodeCopy -->


<link rel="stylesheet" href="/css/clipboard.css">

<script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
  function wait(callback, seconds) {
    var timelag = null;
    timelag = window.setTimeout(callback, seconds);
  }
  !function (e, t, a) {
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '<i class="ri-file-copy-2-line"></i><span>COPY</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      $(".article pre code").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });
      clipboard.on('success', function(e) {
        let $btn = $(e.trigger);
        $btn.addClass('copied');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-checkbox-circle-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPIED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-checkbox-circle-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
      clipboard.on('error', function(e) {
        e.clearSelection();
        let $btn = $(e.trigger);
        $btn.addClass('copy-failed');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-time-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPY FAILED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-time-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
    }
    initCopyCode();
  }(window, document);
</script>


<!-- CanvasBackground -->


<script src="/js/dz.js"></script>



    
  </div>
</body>

</html>